#include "siyi_protocol.hpp"

namespace siyi {

    std::ostream &operator<<(std::ostream &str, const std::vector<std::uint8_t> &bytes) {
        std::ios old_state(nullptr);
        old_state.copyfmt(std::cout);

        for (const auto &byte: bytes) {
            str << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
        }

        std::cout.copyfmt(old_state);

        return str;
    }

    bool Messenger::send(const std::vector<std::uint8_t> &message, std::string log) {
        // Send the UDP packet
        auto msg = message;
        msg.resize(message.size());
        std::cout << "[INFO] " << log << "  send:    " << msg << std::endl;
        int tolen = sizeof(_addr);
        const char *msg_buf = reinterpret_cast<const char*>(message.data());
//        std::cout << "size : " << strlen(msg_buf) << "---" << message.size() << std::endl;
        int sent = sendto(_sockfd, msg_buf, message.size(), 0,
                          (struct sockaddr *) &_addr, tolen);
        if (sent < 0) {
            std::cerr << "Error sending UDP packet: " << strerror(errno) << std::endl;
            return false;
        }
        return true;
    }

//    std::vector<std::uint8_t> Messenger::receive(const std::string &log) const {
//        std::vector<std::uint8_t> result;
//
//        struct timeval tv{};
//        tv.tv_sec = 1;
//        tv.tv_usec = 0;
//
//        fd_set read_fds;
//        FD_ZERO(&read_fds);
//        FD_SET(_sockfd, &read_fds);
//
//        const int select_ret = select(_sockfd + 1, &read_fds, nullptr, nullptr, &tv);
//        if (select_ret > 0) {
//            result.resize(64);
//            const ssize_t recv_ret = recv(_sockfd, result.data(), result.size(), 0);
//            if (recv_ret == -1) {
//                std::cerr << "Error receiving packet: " << strerror(errno) << std::endl;
//                result.resize(0);
//                return result;
//            }
//
//            result.resize(recv_ret);
//
////            std::cout << log << "  received: " << result << std::endl;
//
//        } else if (select_ret == 0) {
//            std::cout << "Timed out." << std::endl;
//
//        } else {
//            std::cerr << "Error with select: " << strerror(errno) << std::endl;
//        }
//
//        return result;
//    }
    std::vector<std::uint8_t> Messenger::receive_once(const std::string &log) {
        char recv_buf[RECV_BUF_SIZE] = {0};
        result.clear();
        int nLen = sizeof(r_addr);
//        std::cout << "nlen1 : " << nLen << std::endl;
        int recv_len = recvfrom(_sockfd, recv_buf, RECV_BUF_SIZE, 0, (struct sockaddr *) &r_addr, &nLen);
//        std::cout << "nlen2 : " << nLen << std::endl;
        if (recv_len < 0) {
            perror("recvfrom");
            return {};
        }
        std::cout << "receive flag : " << recv_len << std::endl;
        result.assign(recv_buf, recv_buf + sizeof(recv_buf) / sizeof(char));
        result.resize(recv_len);
        std::cout << "[INFO] " << log << "  received: " << result << std::endl;
//
        return result;
    }

    void Messenger::receive(std::vector<std::uint8_t> &udp_message, std::uint8_t &cmd_id){
        udp_message.clear();
        cmd_id = 0x00;
        char recv_buf[RECV_BUF_SIZE] = {0};
        int nLen = sizeof(_addr);
//        std::cout << "nlen1 : " << nLen << std::endl;
        int recv_len = recvfrom(_sockfd, recv_buf, RECV_BUF_SIZE, 0, (struct sockaddr *) &_addr, &nLen);
//        std::cout << "nlen2 : " << nLen << std::endl;
        if (recv_len < 0) {
            return;
        }
        std::cout << "receive flag : " << recv_len << std::endl;
        udp_message.assign(recv_buf, recv_buf + sizeof(recv_buf) / sizeof(char));
        udp_message.resize(recv_len);
        std::cout << "[INFO] " << "  received: " << udp_message << std::endl;

        cmd_id = udp_message[7];
    }



} // namespace siyi
